home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 14 / CU Amiga Magazine's Super CD-ROM 14 (1997)(EMAP Images)(GB)(Track 1 of 3)[!][issue 1997-09].iso / CUCD / Programming / Mesa-2.2 / src / matrix.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-03-13  |  21.6 KB  |  821 lines

  1. /* $Id: matrix.c,v 1.10 1997/02/10 19:47:53 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  2.2
  6.  * Copyright (C) 1995-1997  Brian Paul
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Library General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Library General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Library General Public
  19.  * License along with this library; if not, write to the Free
  20.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23.  
  24. /*
  25.  * $Log: matrix.c,v $
  26.  * Revision 1.10  1997/02/10 19:47:53  brianp
  27.  * moved buffer resize code out of gl_Viewport() into gl_ResizeBuffersMESA()
  28.  *
  29.  * Revision 1.9  1997/01/31 23:32:40  brianp
  30.  * now clear depth buffer after reallocation due to window resize
  31.  *
  32.  * Revision 1.8  1997/01/29 19:06:04  brianp
  33.  * removed extra, local definition of Identity[] matrix
  34.  *
  35.  * Revision 1.7  1997/01/28 22:19:17  brianp
  36.  * new matrix inversion code from Stephane Rehel
  37.  *
  38.  * Revision 1.6  1996/12/22 17:53:11  brianp
  39.  * faster invert_matrix() function from scotter@lafn.org
  40.  *
  41.  * Revision 1.5  1996/12/02 18:58:34  brianp
  42.  * gl_rotation_matrix() now returns identity matrix if given a 0 rotation axis
  43.  *
  44.  * Revision 1.4  1996/09/27 01:29:05  brianp
  45.  * added missing default cases to switches
  46.  *
  47.  * Revision 1.3  1996/09/15 14:18:37  brianp
  48.  * now use GLframebuffer and GLvisual
  49.  *
  50.  * Revision 1.2  1996/09/14 06:46:04  brianp
  51.  * better matmul() from Jacques Leroy
  52.  *
  53.  * Revision 1.1  1996/09/13 01:38:16  brianp
  54.  * Initial revision
  55.  *
  56.  */
  57.  
  58.  
  59. /*
  60.  * Matrix operations
  61.  *
  62.  *
  63.  * NOTES:
  64.  * 1. 4x4 transformation matrices are stored in memory in column major order.
  65.  * 2. Points/vertices are to be thought of as column vectors.
  66.  * 3. Transformation of a point p by a matrix M is: p' = M * p
  67.  *
  68.  */
  69.  
  70.  
  71.  
  72. #include <math.h>
  73. #include <stdio.h>
  74. #include <stdlib.h>
  75. #include <string.h>
  76. #include "context.h"
  77. #include "dlist.h"
  78. #include "macros.h"
  79. #include "matrix.h"
  80. #include "types.h"
  81.  
  82.  
  83.  
  84. static GLfloat Identity[16] = {
  85.    1.0, 0.0, 0.0, 0.0,
  86.    0.0, 1.0, 0.0, 0.0,
  87.    0.0, 0.0, 1.0, 0.0,
  88.    0.0, 0.0, 0.0, 1.0
  89. };
  90.  
  91.  
  92.  
  93.  
  94. #ifdef DEBUG
  95. static void print_matrix( const GLfloat m[16] )
  96. {
  97.    int i;
  98.  
  99.    for (i=0;i<4;i++) {
  100.       printf("%f %f %f %f\n", m[i], m[4+i], m[8+i], m[12+i] );
  101.    }
  102. }
  103. #endif
  104.  
  105.  
  106.  
  107. /*
  108.  * Perform a 4x4 matrix multiplication  (product = a x b).
  109.  * Input:  a, b - matrices to multiply
  110.  * Output:  product - product of a and b
  111.  * WARNING: (product != b) assumed
  112.  * NOTE:    (product == a) allowed    
  113.  */
  114. static void matmul( GLfloat *product, const GLfloat *a, const GLfloat *b )
  115. {
  116.    /* This matmul was contributed by Thomas Malik */
  117.    GLint i;
  118.  
  119. #define A(row,col)  a[(col<<2)+row]
  120. #define B(row,col)  b[(col<<2)+row]
  121. #define P(row,col)  product[(col<<2)+row]
  122.  
  123.    /* i-te Zeile */
  124.    for (i = 0; i < 4; i++) {
  125.       GLfloat ai0=A(i,0),  ai1=A(i,1),  ai2=A(i,2),  ai3=A(i,3);
  126.       P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0);
  127.       P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1);
  128.       P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2);
  129.       P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3);
  130.    }
  131.  
  132. #undef A
  133. #undef B
  134. #undef P
  135. }
  136.  
  137.  
  138.  
  139. /*
  140.  * Compute the inverse of a 4x4 matrix.  Contributed by scotter@lafn.org
  141.  */
  142. static void invert_matrix_general( const GLfloat *m, GLfloat *out )
  143. {
  144.  
  145. /* NB. OpenGL Matrices are COLUMN major. */
  146. #define MAT(m,r,c) (m)[(c)*4+(r)]
  147.  
  148. /* Here's some shorthand converting standard (row,column) to index. */
  149. #define m11 MAT(m,0,0)
  150. #define m12 MAT(m,0,1)
  151. #define m13 MAT(m,0,2)
  152. #define m14 MAT(m,0,3)
  153. #define m21 MAT(m,1,0)
  154. #define m22 MAT(m,1,1)
  155. #define m23 MAT(m,1,2)
  156. #define m24 MAT(m,1,3)
  157. #define m31 MAT(m,2,0)
  158. #define m32 MAT(m,2,1)
  159. #define m33 MAT(m,2,2)
  160. #define m34 MAT(m,2,3)
  161. #define m41 MAT(m,3,0)
  162. #define m42 MAT(m,3,1)
  163. #define m43 MAT(m,3,2)
  164. #define m44 MAT(m,3,3)
  165.  
  166.    GLfloat det;
  167.    GLfloat d12, d13, d23, d24, d34, d41;
  168.    GLfloat tmp[16]; /* Allow out == in. */
  169.  
  170.    /* Inverse = adjoint / det. (See linear algebra texts.)*/
  171.  
  172.    /* pre-compute 2x2 dets for last two rows when computing */
  173.    /* cofactors of first two rows. */
  174.    d12 = (m31*m42-m41*m32);
  175.    d13 = (m31*m43-m41*m33);
  176.    d23 = (m32*m43-m42*m33);
  177.    d24 = (m32*m44-m42*m34);
  178.    d34 = (m33*m44-m43*m34);
  179.    d41 = (m34*m41-m44*m31);
  180.  
  181.    tmp[0] =  (m22 * d34 - m23 * d24 + m24 * d23);
  182.    tmp[1] = -(m21 * d34 + m23 * d41 + m24 * d13);
  183.    tmp[2] =  (m21 * d24 + m22 * d41 + m24 * d12);
  184.    tmp[3] = -(m21 * d23 - m22 * d13 + m23 * d12);
  185.  
  186.    /* Compute determinant as early as possible using these cofactors. */
  187.    det = m11 * tmp[0] + m12 * tmp[1] + m13 * tmp[2] + m14 * tmp[3];
  188.  
  189.    /* Run singularity test. */
  190.    if (det == 0.0F) {
  191.       /* printf("invert_matrix: Warning: Singular matrix.\n"); */
  192.       MEMCPY( out, Identity, 16*sizeof(GLfloat) );
  193.    }
  194.    else {
  195.       GLfloat invDet = 1.0F / det;
  196.       /* Compute rest of inverse. */
  197.       tmp[0] *= invDet;
  198.       tmp[1] *= invDet;
  199.       tmp[2] *= invDet;
  200.       tmp[3] *= invDet;
  201.  
  202.       tmp[4] = -(m12 * d34 - m13 * d24 + m14 * d23) * invDet;
  203.       tmp[5] =  (m11 * d34 + m13 * d41 + m14 * d13) * invDet;
  204.       tmp[6] = -(m11 * d24 + m12 * d41 + m14 * d12) * invDet;
  205.       tmp[7] =  (m11 * d23 - m12 * d13 + m13 * d12) * invDet;
  206.  
  207.       /* Pre-compute 2x2 dets for first two rows when computing */
  208.       /* cofactors of last two rows. */
  209.       d12 = m11*m22-m21*m12;
  210.       d13 = m11*m23-m21*m13;
  211.       d23 = m12*m23-m22*m13;
  212.       d24 = m12*m24-m22*m14;
  213.       d34 = m13*m24-m23*m14;
  214.       d41 = m14*m21-m24*m11;
  215.  
  216.       tmp[8] =  (m42 * d34 - m43 * d24 + m44 * d23) * invDet;
  217.       tmp[9] = -(m41 * d34 + m43 * d41 + m44 * d13) * invDet;
  218.       tmp[10] =  (m41 * d24 + m42 * d41 + m44 * d12) * invDet;
  219.       tmp[11] = -(m41 * d23 - m42 * d13 + m43 * d12) * invDet;
  220.       tmp[12] = -(m32 * d34 - m33 * d24 + m34 * d23) * invDet;
  221.       tmp[13] =  (m31 * d34 + m33 * d41 + m34 * d13) * invDet;
  222.       tmp[14] = -(m31 * d24 + m32 * d41 + m34 * d12) * invDet;
  223.       tmp[15] =  (m31 * d23 - m32 * d13 + m33 * d12) * invDet;
  224.  
  225.       MEMCPY(out, tmp, 16*sizeof(GLfloat));
  226.    }
  227.  
  228. #undef m11
  229. #undef m12
  230. #undef m13
  231. #undef m14
  232. #undef m21
  233. #undef m22
  234. #undef m23
  235. #undef m24
  236. #undef m31
  237. #undef m32
  238. #undef m33
  239. #undef m34
  240. #undef m41
  241. #undef m42
  242. #undef m43
  243. #undef m44
  244. #undef MAT
  245. }
  246.  
  247.  
  248. /*
  249.  * Invert matrix m.  This algorithm contributed by Stephane Rehel
  250.  * <rehel@worldnet.fr>
  251.  */
  252. static void invert_matrix( const GLfloat *m, GLfloat *out )
  253. {
  254. /* NB. OpenGL Matrices are COLUMN major. */
  255. #define MAT(m,r,c) (m)[(c)*4+(r)]
  256.  
  257. /* Here's some shorthand converting standard (row,column) to index. */
  258. #define m11 MAT(m,0,0)
  259. #define m12 MAT(m,0,1)
  260. #define m13 MAT(m,0,2)
  261. #define m14 MAT(m,0,3)
  262. #define m21 MAT(m,1,0)
  263. #define m22 MAT(m,1,1)
  264. #define m23 MAT(m,1,2)
  265. #define m24 MAT(m,1,3)
  266. #define m31 MAT(m,2,0)
  267. #define m32 MAT(m,2,1)
  268. #define m33 MAT(m,2,2)
  269. #define m34 MAT(m,2,3)
  270. #define m41 MAT(m,3,0)
  271. #define m42 MAT(m,3,1)
  272. #define m43 MAT(m,3,2)
  273. #define m44 MAT(m,3,3)
  274.  
  275.    register GLfloat det;
  276.    GLfloat tmp[16]; /* Allow out == in. */
  277.  
  278.    if( m41 != 0. || m42 != 0. || m43 != 0. || m44 != 1. ) {
  279.       invert_matrix_general(m, out);
  280.       return;
  281.    }
  282.  
  283.    /* Inverse = adjoint / det. (See linear algebra texts.)*/
  284.  
  285.    tmp[0]= m22 * m33 - m23 * m32;
  286.    tmp[1]= m23 * m31 - m21 * m33;
  287.    tmp[2]= m21 * m32 - m22 * m31;
  288.  
  289.    /* Compute determinant as early as possible using these cofactors. */
  290.    det= m11 * tmp[0] + m12 * tmp[1] + m13 * tmp[2];
  291.  
  292.    /* Run singularity test. */
  293.    if (det == 0.0F) {
  294.       /* printf("invert_matrix: Warning: Singular matrix.\n"); */
  295.       MEMCPY( out, Identity, 16*sizeof(GLfloat) );
  296.    }
  297.    else {
  298.       GLfloat d12, d13, d23, d24, d34, d41;
  299.       register GLfloat im11, im12, im13, im14;
  300.  
  301.       det= 1. / det;
  302.  
  303.       /* Compute rest of inverse. */
  304.       tmp[0] *= det;
  305.       tmp[1] *= det;
  306.       tmp[2] *= det;
  307.       tmp[3]  = 0.;
  308.  
  309.       im11= m11 * det;
  310.       im12= m12 * det;
  311.       im13= m13 * det;
  312.       im14= m14 * det;
  313.       tmp[4] = im13 * m32 - im12 * m33;
  314.       tmp[5] = im11 * m33 - im13 * m31;
  315.       tmp[6] = im12 * m31 - im11 * m32;
  316.       tmp[7] = 0.;
  317.  
  318.       /* Pre-compute 2x2 dets for first two rows when computing */
  319.       /* cofactors of last two rows. */
  320.       d12 = im11*m22 - m21*im12;
  321.       d13 = im11*m23 - m21*im13;
  322.       d23 = im12*m23 - m22*im13;
  323.       d24 = im12*m24 - m22*im14;
  324.       d34 = im13*m24 - m23*im14;
  325.       d41 = im14*m21 - m24*im11;
  326.  
  327.       tmp[8] =  d23;
  328.       tmp[9] = -d13;
  329.       tmp[10] = d12;
  330.       tmp[11] = 0.;
  331.  
  332.       tmp[12] = -(m32 * d34 - m33 * d24 + m34 * d23);
  333.       tmp[13] =  (m31 * d34 + m33 * d41 + m34 * d13);
  334.       tmp[14] = -(m31 * d24 + m32 * d41 + m34 * d12);
  335.       tmp[15] =  1.;
  336.  
  337.       MEMCPY(out, tmp, 16*sizeof(GLfloat));
  338.   }
  339.  
  340. #undef m11
  341. #undef m12
  342. #undef m13
  343. #undef m14
  344. #undef m21
  345. #undef m22
  346. #undef m23
  347. #undef m24
  348. #undef m31
  349. #undef m32
  350. #undef m33
  351. #undef m34
  352. #undef m41
  353. #undef m42
  354. #undef m43
  355. #undef m44
  356. #undef MAT
  357. }
  358.  
  359.  
  360. /*
  361.  * Compute the inverse of the current ModelViewMatrix.
  362.  */
  363. void gl_compute_modelview_inverse( GLcontext *ctx )
  364. {
  365.    invert_matrix( ctx->ModelViewMatrix, ctx->ModelViewInv );
  366.    ctx->ModelViewInvValid = GL_TRUE;
  367. }
  368.  
  369.  
  370.  
  371.  
  372. /*
  373.  * Determine if the given matrix is the identity matrix.
  374.  */
  375. static GLboolean is_identity( const GLfloat m[16] )
  376. {
  377.    if (   m[0]==1.0F && m[4]==0.0F && m[ 8]==0.0F && m[12]==0.0F
  378.        && m[1]==0.0F && m[5]==1.0F && m[ 9]==0.0F && m[13]==0.0F
  379.        && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F
  380.        && m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
  381.       return GL_TRUE;
  382.    }
  383.    else {
  384.       return GL_FALSE;
  385.    }
  386. }
  387.  
  388.  
  389.  
  390.  
  391. void gl_Frustum( GLcontext *ctx,
  392.                  GLdouble left, GLdouble right,
  393.           GLdouble bottom, GLdouble top,
  394.          GLdouble nearval, GLdouble farval )
  395. {
  396.    GLfloat x, y, a, b, c, d;
  397.    GLfloat m[16];
  398.  
  399.    if (nearval<=0.0 || farval<=0.0) {
  400.       gl_error( ctx,  GL_INVALID_VALUE, "glFrustum(near or far)" );
  401.    }
  402.  
  403.    x = (2.0*nearval) / (right-left);
  404.    y = (2.0*nearval) / (top-bottom);
  405.    a = (right+left) / (right-left);
  406.    b = (top+bottom) / (top-bottom);
  407.    c = -(farval+nearval) / ( farval-nearval);
  408.    d = -(2.0*farval*nearval) / (farval-nearval);  /* error? */
  409.  
  410. #define M(row,col)  m[col*4+row]
  411.    M(0,0) = x;     M(0,1) = 0.0F;  M(0,2) = a;      M(0,3) = 0.0F;
  412.    M(1,0) = 0.0F;  M(1,1) = y;     M(1,2) = b;      M(1,3) = 0.0F;
  413.    M(2,0) = 0.0F;  M(2,1) = 0.0F;  M(2,2) = c;      M(2,3) = d;
  414.    M(3,0) = 0.0F;  M(3,1) = 0.0F;  M(3,2) = -1.0F;  M(3,3) = 0.0F;
  415. #undef M
  416.  
  417.    gl_MultMatrixf( ctx, m );
  418. }
  419.  
  420.  
  421.  
  422. void gl_MatrixMode( GLcontext *ctx, GLenum mode )
  423. {
  424.    if (INSIDE_BEGIN_END(ctx)) {
  425.       gl_error( ctx,  GL_INVALID_OPERATION, "glMatrixMode" );
  426.       return;
  427.    }
  428.    switch (mode) {
  429.       case GL_MODELVIEW:
  430.       case GL_PROJECTION:
  431.       case GL_TEXTURE:
  432.          ctx->Transform.MatrixMode = mode;
  433.          break;
  434.       default:
  435.          gl_error( ctx,  GL_INVALID_ENUM, "glMatrixMode" );
  436.    }
  437. }
  438.  
  439.  
  440.  
  441. void gl_PushMatrix( GLcontext *ctx )
  442. {
  443.    if (INSIDE_BEGIN_END(ctx)) {
  444.       gl_error( ctx,  GL_INVALID_OPERATION, "glPushMatrix" );
  445.       return;
  446.    }
  447.    switch (ctx->Transform.MatrixMode) {
  448.       case GL_MODELVIEW:
  449.          if (ctx->ModelViewStackDepth>=MAX_MODELVIEW_STACK_DEPTH-1) {
  450.             gl_error( ctx,  GL_STACK_OVERFLOW, "glPushMatrix");
  451.             return;
  452.          }
  453.          MEMCPY( ctx->ModelViewStack[ctx->ModelViewStackDepth],
  454.                  ctx->ModelViewMatrix,
  455.                  16*sizeof(GLfloat) );
  456.          ctx->ModelViewStackDepth++;
  457.          break;
  458.       case GL_PROJECTION:
  459.          if (ctx->ProjectionStackDepth>=MAX_PROJECTION_STACK_DEPTH) {
  460.             gl_error( ctx,  GL_STACK_OVERFLOW, "glPushMatrix");
  461.             return;
  462.          }
  463.          MEMCPY( ctx->ProjectionStack[ctx->ProjectionStackDepth],
  464.                  ctx->ProjectionMatrix,
  465.                  16*sizeof(GLfloat) );
  466.          ctx->ProjectionStackDepth++;
  467.          break;
  468.       case GL_TEXTURE:
  469.          if (ctx->TextureStackDepth>=MAX_TEXTURE_STACK_DEPTH) {
  470.             gl_error( ctx,  GL_STACK_OVERFLOW, "glPushMatrix");
  471.             return;
  472.          }
  473.          MEMCPY( ctx->TextureStack[ctx->TextureStackDepth],
  474.                  ctx->TextureMatrix,
  475.                  16*sizeof(GLfloat) );
  476.          ctx->TextureStackDepth++;
  477.          break;
  478.       default:
  479.          abort();
  480.    }
  481. }
  482.  
  483.  
  484.  
  485. void gl_PopMatrix( GLcontext *ctx )
  486. {
  487.    if (INSIDE_BEGIN_END(ctx)) {
  488.       gl_error( ctx,  GL_INVALID_OPERATION, "glPopMatrix" );
  489.       return;
  490.    }
  491.    switch (ctx->Transform.MatrixMode) {
  492.       case GL_MODELVIEW:
  493.          if (ctx->ModelViewStackDepth==0) {
  494.             gl_error( ctx,  GL_STACK_UNDERFLOW, "glPopMatrix");
  495.             return;
  496.          }
  497.          ctx->ModelViewStackDepth--;
  498.          MEMCPY( ctx->ModelViewMatrix,
  499.                  ctx->ModelViewStack[ctx->ModelViewStackDepth],
  500.                  16*sizeof(GLfloat) );
  501.          ctx->ModelViewInvValid = GL_FALSE;
  502.          break;
  503.       case GL_PROJECTION:
  504.          if (ctx->ProjectionStackDepth==0) {
  505.             gl_error( ctx,  GL_STACK_UNDERFLOW, "glPopMatrix");
  506.             return;
  507.          }
  508.          ctx->ProjectionStackDepth--;
  509.          MEMCPY( ctx->ProjectionMatrix,
  510.                  ctx->ProjectionStack[ctx->ProjectionStackDepth],
  511.                  16*sizeof(GLfloat) );
  512.          break;
  513.       case GL_TEXTURE:
  514.          if (ctx->TextureStackDepth==0) {
  515.             gl_error( ctx,  GL_STACK_UNDERFLOW, "glPopMatrix");
  516.             return;
  517.          }
  518.          ctx->TextureStackDepth--;
  519.          MEMCPY( ctx->TextureMatrix,
  520.                  ctx->TextureStack[ctx->TextureStackDepth],
  521.                  16*sizeof(GLfloat) );
  522.          ctx->IdentityTexMat = is_identity( ctx->TextureMatrix );
  523.          break;
  524.       default:
  525.          abort();
  526.    }
  527. }
  528.  
  529.  
  530.  
  531. void gl_LoadMatrixf( GLcontext *ctx, const GLfloat *m )
  532. {
  533.    if (INSIDE_BEGIN_END(ctx)) {
  534.       gl_error( ctx,  GL_INVALID_OPERATION, "glLoadMatrix" );
  535.       return;
  536.    }
  537.    switch (ctx->Transform.MatrixMode) {
  538.       case GL_MODELVIEW:
  539.          MEMCPY( ctx->ModelViewMatrix, m, 16*sizeof(GLfloat) );
  540.      ctx->ModelViewInvValid = GL_FALSE;
  541.      break;
  542.       case GL_PROJECTION:
  543.      MEMCPY( ctx->ProjectionMatrix, m, 16*sizeof(GLfloat) );
  544.      break;
  545.       case GL_TEXTURE:
  546.      MEMCPY( ctx->TextureMatrix, m, 16*sizeof(GLfloat) );
  547.          ctx->IdentityTexMat = is_identity( ctx->TextureMatrix );
  548.      break;
  549.       default:
  550.          abort();
  551.    }
  552. }
  553.  
  554.  
  555.  
  556. void gl_MultMatrixf( GLcontext *ctx, const GLfloat *m )
  557. {
  558.    if (INSIDE_BEGIN_END(ctx)) {
  559.       gl_error( ctx,  GL_INVALID_OPERATION, "glMultMatrix" );
  560.       return;
  561.    }
  562.    switch (ctx->Transform.MatrixMode) {
  563.       case GL_MODELVIEW:
  564.          matmul( ctx->ModelViewMatrix, ctx->ModelViewMatrix, m );
  565.      ctx->ModelViewInvValid = GL_FALSE;
  566.      break;
  567.       case GL_PROJECTION:
  568.      matmul( ctx->ProjectionMatrix, ctx->ProjectionMatrix, m );
  569.      break;
  570.       case GL_TEXTURE:
  571.      matmul( ctx->TextureMatrix, ctx->TextureMatrix, m );
  572.          ctx->IdentityTexMat = is_identity( ctx->TextureMatrix );
  573.      break;
  574.       default:
  575.          abort();
  576.    }
  577. }
  578.  
  579.  
  580.  
  581. /*
  582.  * Generate a 4x4 transformation matrix from glRotate parameters.
  583.  */
  584. void gl_rotation_matrix( GLfloat angle, GLfloat x, GLfloat y, GLfloat z,
  585.                          GLfloat m[] )
  586. {
  587.    /* This function contributed by Erich Boleyn (erich@uruk.org) */
  588.    GLfloat mag, s, c;
  589.    GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c;
  590.  
  591.    s = sin( angle * (M_PI / 180.0) );
  592.    c = cos( angle * (M_PI / 180.0) );
  593.  
  594.    mag = sqrt( x*x + y*y + z*z );
  595.  
  596.    if (mag == 0.0) {
  597.       /* generate an identity matrix and return */
  598.       MEMCPY(m, Identity, sizeof(GLfloat)*16);
  599.       return;
  600.    }
  601.  
  602.    x /= mag;
  603.    y /= mag;
  604.    z /= mag;
  605.  
  606. #define M(row,col)  m[col*4+row]
  607.  
  608.    /*
  609.     *     Arbitrary axis rotation matrix.
  610.     *
  611.     *  This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied
  612.     *  like so:  Rz * Ry * T * Ry' * Rz'.  T is the final rotation
  613.     *  (which is about the X-axis), and the two composite transforms
  614.     *  Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary
  615.     *  from the arbitrary axis to the X-axis then back.  They are
  616.     *  all elementary rotations.
  617.     *
  618.     *  Rz' is a rotation about the Z-axis, to bring the axis vector
  619.     *  into the x-z plane.  Then Ry' is applied, rotating about the
  620.     *  Y-axis to bring the axis vector parallel with the X-axis.  The
  621.     *  rotation about the X-axis is then performed.  Ry and Rz are
  622.     *  simply the respective inverse transforms to bring the arbitrary
  623.     *  axis back to it's original orientation.  The first transforms
  624.     *  Rz' and Ry' are considered inverses, since the data from the
  625.     *  arbitrary axis gives you info on how to get to it, not how
  626.     *  to get away from it, and an inverse must be applied.
  627.     *
  628.     *  The basic calculation used is to recognize that the arbitrary
  629.     *  axis vector (x, y, z), since it is of unit length, actually
  630.     *  represents the sines and cosines of the angles to rotate the
  631.     *  X-axis to the same orientation, with theta being the angle about
  632.     *  Z and phi the angle about Y (in the order described above)
  633.     *  as follows:
  634.     *
  635.     *  cos ( theta ) = x / sqrt ( 1 - z^2 )
  636.     *  sin ( theta ) = y / sqrt ( 1 - z^2 )
  637.     *
  638.     *  cos ( phi ) = sqrt ( 1 - z^2 )
  639.     *  sin ( phi ) = z
  640.     *
  641.     *  Note that cos ( phi ) can further be inserted to the above
  642.     *  formulas:
  643.     *
  644.     *  cos ( theta ) = x / cos ( phi )
  645.     *  sin ( theta ) = y / sin ( phi )
  646.     *
  647.     *  ...etc.  Because of those relations and the standard trigonometric
  648.     *  relations, it is pssible to reduce the transforms down to what
  649.     *  is used below.  It may be that any primary axis chosen will give the
  650.     *  same results (modulo a sign convention) using thie method.
  651.     *
  652.     *  Particularly nice is to notice that all divisions that might
  653.     *  have caused trouble when parallel to certain planes or
  654.     *  axis go away with care paid to reducing the expressions.
  655.     *  After checking, it does perform correctly under all cases, since
  656.     *  in all the cases of division where the denominator would have
  657.     *  been zero, the numerator would have been zero as well, giving
  658.     *  the expected result.
  659.     */
  660.  
  661.    xx = x * x;
  662.    yy = y * y;
  663.    zz = z * z;
  664.    xy = x * y;
  665.    yz = y * z;
  666.    zx = z * x;
  667.    xs = x * s;
  668.    ys = y * s;
  669.    zs = z * s;
  670.    one_c = 1.0F - c;
  671.  
  672.    M(0,0) = (one_c * xx) + c;
  673.    M(0,1) = (one_c * xy) - zs;
  674.    M(0,2) = (one_c * zx) + ys;
  675.    M(0,3) = 0.0F;
  676.  
  677.    M(1,0) = (one_c * xy) + zs;
  678.    M(1,1) = (one_c * yy) + c;
  679.    M(1,2) = (one_c * yz) - xs;
  680.    M(1,3) = 0.0F;
  681.  
  682.    M(2,0) = (one_c * zx) - ys;
  683.    M(2,1) = (one_c * yz) + xs;
  684.    M(2,2) = (one_c * zz) + c;
  685.    M(2,3) = 0.0F;
  686.  
  687.    M(3,0) = 0.0F;
  688.    M(3,1) = 0.0F;
  689.    M(3,2) = 0.0F;
  690.    M(3,3) = 1.0F;
  691.  
  692. #undef M
  693. }
  694.  
  695.  
  696.  
  697. void gl_Rotatef( GLcontext *ctx,
  698.                  GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
  699. {
  700.    GLfloat m[16];
  701.    gl_rotation_matrix( angle, x, y, z, m );
  702.    gl_MultMatrixf( ctx, m );
  703. }
  704.  
  705.  
  706.  
  707. /*
  708.  * Execute a glScale call
  709.  */
  710. void gl_Scalef( GLcontext *ctx, GLfloat x, GLfloat y, GLfloat z )
  711. {
  712.    GLfloat *m;
  713.  
  714.    if (INSIDE_BEGIN_END(ctx)) {
  715.       gl_error( ctx,  GL_INVALID_OPERATION, "glScale" );
  716.       return;
  717.    }
  718.    switch (ctx->Transform.MatrixMode) {
  719.       case GL_MODELVIEW:
  720.          m = ctx->ModelViewMatrix;
  721.      ctx->ModelViewInvValid = GL_FALSE;
  722.      break;
  723.       case GL_PROJECTION:
  724.          m = ctx->ProjectionMatrix;
  725.      break;
  726.       case GL_TEXTURE:
  727.          m = ctx->TextureMatrix;
  728.      break;
  729.       default:
  730.          abort();
  731.    }
  732.    m[0] *= x;   m[4] *= y;   m[8]  *= z;
  733.    m[1] *= x;   m[5] *= y;   m[9]  *= z;
  734.    m[2] *= x;   m[6] *= y;   m[10] *= z;
  735.    m[3] *= x;   m[7] *= y;   m[11] *= z;
  736.  
  737.    if (ctx->Transform.MatrixMode==GL_TEXTURE) {
  738.       ctx->IdentityTexMat = is_identity( ctx->TextureMatrix );
  739.    }
  740. }
  741.  
  742.  
  743.  
  744. /*
  745.  * Execute a glTranslate call
  746.  */
  747. void gl_Translatef( GLcontext *ctx, GLfloat x, GLfloat y, GLfloat z )
  748. {
  749.    GLfloat *m;
  750.    if (INSIDE_BEGIN_END(ctx)) {
  751.       gl_error( ctx, GL_INVALID_OPERATION, "glTranslate" );
  752.       return;
  753.    }
  754.    switch (ctx->Transform.MatrixMode) {
  755.       case GL_MODELVIEW:
  756.          m = ctx->ModelViewMatrix;
  757.      ctx->ModelViewInvValid = GL_FALSE;
  758.      break;
  759.       case GL_PROJECTION:
  760.          m = ctx->ProjectionMatrix;
  761.      break;
  762.       case GL_TEXTURE:
  763.          m = ctx->TextureMatrix;
  764.      break;
  765.       default:
  766.          abort();
  767.    }
  768.  
  769.    m[12] = m[0] * x + m[4] * y + m[8]  * z + m[12];
  770.    m[13] = m[1] * x + m[5] * y + m[9]  * z + m[13];
  771.    m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];
  772.    m[15] = m[3] * x + m[7] * y + m[11] * z + m[15];
  773.  
  774.    if (ctx->Transform.MatrixMode==GL_TEXTURE) {
  775.       ctx->IdentityTexMat = is_identity( ctx->TextureMatrix );
  776.    }
  777. }
  778.  
  779.  
  780.  
  781.  
  782. /*
  783.  * Define a new viewport and reallocate auxillary buffers if the size of
  784.  * the window (color buffer) has changed.
  785.  */
  786. void gl_Viewport( GLcontext *ctx,
  787.                   GLint x, GLint y, GLsizei width, GLsizei height )
  788. {
  789.    if (width<0 || height<0) {
  790.       gl_error( ctx,  GL_INVALID_VALUE, "glViewport" );
  791.       return;
  792.    }
  793.    if (INSIDE_BEGIN_END(ctx)) {
  794.       gl_error( ctx,  GL_INVALID_OPERATION, "glViewport" );
  795.       return;
  796.    }
  797.  
  798.    /* clamp width, and height to implementation dependent range */
  799.    width  = CLAMP( width,  1, MAX_WIDTH );
  800.    height = CLAMP( height, 1, MAX_HEIGHT );
  801.  
  802.    /* Save viewport */
  803.    ctx->Viewport.X = x;
  804.    ctx->Viewport.Width = width;
  805.    ctx->Viewport.Y = y;
  806.    ctx->Viewport.Height = height;
  807.  
  808.    /* compute scale and bias values */
  809.    ctx->Viewport.Sx = (GLfloat) width / 2.0F;
  810.    ctx->Viewport.Tx = ctx->Viewport.Sx + x;
  811.    ctx->Viewport.Sy = (GLfloat) height / 2.0F;
  812.    ctx->Viewport.Ty = ctx->Viewport.Sy + y;
  813.  
  814.    ctx->NewState |= NEW_ALL;   /* just to be safe */
  815.  
  816.    /* Check if window/buffer has been resized and if so, reallocate the
  817.     * ancillary buffers.
  818.     */
  819.    gl_ResizeBuffersMESA(ctx);
  820. }
  821.